﻿using Microsoft.SqlServer.Server;
using SketchUpAPI.NET.Enums;
using SketchUpAPI.NET.SketchUp.Exception;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace SketchUpAPI.NET.Objects
{
    /// <summary>
    /// 接收多边形的拓扑关系，一个常见的用法是，接收<see cref="Face"/>面的环，用中读取拓扑关系
    /// </summary>
    public class EdgeUse : Entity
    {
        #region API 函数
        /// <summary>
        /// 获取对应边缘
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="edge">返回，边缘 <see cref="Objects.Edge"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetEdge(IntPtr edgeuse, ref IntPtr edge);

        /// <summary>
        /// 获取所属的环
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="loop">返回，环 <see cref="Objects.Loop"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetLoop(IntPtr edgeuse, out IntPtr loop);

        /// <summary>
        /// 获取所属的面
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="face">返回，面 <see cref="Objects.Face"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetFace(IntPtr edgeuse, out IntPtr face);

        /// <summary>
        /// 获取与该实例相连的 <see cref="Objects.EdgeUse"/> 个数
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="count">个数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetNumPartners(IntPtr edgeuse, out long count);

        /// <summary>
        /// 获取与该实例相连的全部 <see cref="Objects.EdgeUse"/>
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="len">总数</param>
        /// <param name="partners">记录相连的 <see cref="Objects.EdgeUse"/></param>
        /// <param name="realcount">真实的总数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetPartners(IntPtr edgeuse, long len, IntPtr[] partners, out long realcount);

        /// <summary>
        /// 判断方向是否被反转了
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="reversed">返回，是否被反转了</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseIsReversed(IntPtr edgeuse, out bool reversed);

        /// <summary>
        /// 获取前一个与其相连的 <see cref="Objects.EdgeUse"/>
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="prev_edgeuse">前一个 <see cref="Objects.EdgeUse"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetPrevious(IntPtr edgeuse, out IntPtr prev_edgeuse);

        /// <summary>
        /// 获取下一个与其相连的 <see cref="Objects.EdgeUse"/>
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="next_edgeuse">下一个 <see cref="Objects.EdgeUse"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetNext(IntPtr edgeuse, out IntPtr next_edgeuse);

        /// <summary>
        /// 获取起点
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="vertex">起点 <see cref="Objects.Vertex"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetStartVertex(IntPtr edgeuse, out IntPtr vertex);

        /// <summary>
        /// 获取终点
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="vertex">终点 <see cref="Objects.Vertex"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetEndVertex(IntPtr edgeuse, out IntPtr vertex);

        /// <summary>
        /// 获取起点处的法向
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="normal">起点处法向</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetStartVertexNormal(IntPtr edgeuse, ref Vector3D normal);

        /// <summary>
        /// 获取终点处法向
        /// </summary>
        /// <param name="edgeuse"></param>
        /// <param name="normal">终点处法向</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUEdgeUseGetEndVertexNormal(IntPtr edgeuse, ref Vector3D normal);
        #endregion

        /// <summary>
        /// 是否反转方向
        /// </summary>
        public bool IsReversed
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseIsReversed(Id, out bool reversed));
                return reversed;
            }
        }

        /// <summary>
        /// 对应的边
        /// </summary>
        public Edge Edge
        {
            get
            {
                IntPtr id = IntPtr.Zero;
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetEdge(Id, ref id));
                return new Edge(id);
            }
        }

        /// <summary>
        /// 获取该边所在的环
        /// </summary>
        public Loop Loop
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetLoop(Id, out IntPtr id));
                return new Loop(id);
            }
        }

        /// <summary>
        /// 所属的面
        /// </summary>
        public Face Face
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetFace(Id, out IntPtr id));
                return new Face(id);
            }
        }

        /// <summary>
        /// 获取相连的<see cref="EdgeUse"/>
        /// </summary>
        public List<EdgeUse> Parters
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetNumPartners(Id, out long count));
                IntPtr[] pts = new IntPtr[count];
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetPartners(Id, count, pts, out long realcount));
                return pts.Select(i => new EdgeUse(i)).ToList();
            }
        }

        /// <summary>
        /// 获取前一个相连的 <see cref="EdgeUse"/>
        /// </summary>
        public EdgeUse Previous
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetPrevious(Id, out IntPtr id));
                return new EdgeUse(id);
            }
        }

        /// <summary>
        /// 获取下一个相连的 <see cref="EdgeUse"/>
        /// </summary>
        public EdgeUse Next
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetNext(Id, out IntPtr id));
                return new EdgeUse(id);
            }
        }

        /// <summary>
        /// 起点
        /// </summary>
        public Vertex Start
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetStartVertex(Id, out IntPtr id));
                return new Vertex(id);
            }
        }

        /// <summary>
        /// 起点法向
        /// </summary>
        public Vector3D StartNormal
        {
            get
            {
                Vector3D v = new Vector3D();
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetStartVertexNormal(Id, ref v));
                return v;
            }
        }

        /// <summary>
        /// 终点
        /// </summary>
        public Vertex End
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetEndVertex(Id, out IntPtr id));
                return new Vertex(id);
            }
        }

        /// <summary>
        /// 终点法向
        /// </summary>
        public Vector3D EndNormal
        {
            get
            {
                Vector3D v = new Vector3D();
                SketchUpExceptionHelper.ThrowSUResult(SUEdgeUseGetEndVertexNormal(Id, ref v));
                return v;
            }
        }

        internal EdgeUse(IntPtr id) : base(id) { }
    }
}